package com.ikingtech.platform.service.system.dict.controller;

import com.ikingtech.framework.sdk.base.model.BatchParam;
import com.ikingtech.framework.sdk.base.model.DragOrderParam;
import com.ikingtech.framework.sdk.context.security.Me;
import com.ikingtech.framework.sdk.context.exception.FrameworkException;
import com.ikingtech.framework.sdk.core.response.R;
import com.ikingtech.framework.sdk.data.helper.DragHelper;
import com.ikingtech.framework.sdk.data.helper.DragHelperBuilder;
import com.ikingtech.framework.sdk.dict.api.DictItemApi;
import com.ikingtech.framework.sdk.dict.model.DictItemDTO;
import com.ikingtech.framework.sdk.dict.model.DictItemQueryParamDTO;
import com.ikingtech.framework.sdk.enums.common.DragTargetPositionEnum;
import com.ikingtech.framework.sdk.enums.domain.DomainEnum;
import com.ikingtech.framework.sdk.enums.system.dictionary.DictItemEnum;
import com.ikingtech.framework.sdk.enums.system.dictionary.DictTypeEnum;
import com.ikingtech.framework.sdk.log.embedded.annotation.OperationLog;
import com.ikingtech.framework.sdk.utils.Tools;
import com.ikingtech.framework.sdk.web.annotation.ApiController;
import com.ikingtech.platform.service.system.dict.entity.DictDO;
import com.ikingtech.platform.service.system.dict.entity.DictItemDO;
import com.ikingtech.platform.service.system.dict.exception.DictExceptionInfo;
import com.ikingtech.platform.service.system.dict.service.DictItemService;
import com.ikingtech.platform.service.system.dict.service.DictService;
import lombok.RequiredArgsConstructor;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * 系统管理-字典项管理
 * <p>1. 字典项需按租户隔离
 * <p>2. 字典项支持父子级关系
 *
 * @author tie yan
 */
@RequiredArgsConstructor
@ApiController(value = "/system/dict/item", name = "系统管理-字典项管理", description = "系统管理-字典项管理")
public class DictItemController implements DictItemApi {

    private final DictItemService service;

    private final DictService dictService;

    @Override
    @OperationLog(value = "新增字典项", dataId = "#_res.getData()")
    @Transactional(rollbackFor = Exception.class)
    public R<String> add(DictItemDTO item) {
        String tenantCode = Me.tenantCode();
        if (Boolean.TRUE.equals(this.service.labelExist(item.getDictId(), item.getValue(), tenantCode))) {
            throw new FrameworkException(DictExceptionInfo.DUPLICATE_DICT_ITEM_LABEL);
        }
        DictDO dictEntity = this.dictService.getById(item.getDictId());
        if (DictTypeEnum.SYSTEM.name().equals(dictEntity.getType())) {
            throw new FrameworkException(DictExceptionInfo.ADD_SYSTEM_DICT_ITEM_IS_NOT_ALLOWED);
        }

        DictItemDO entity = Tools.Bean.copy(item, DictItemDO.class);
        entity.setId(Tools.Id.uuid());
        entity.setTenantCode(tenantCode);
        entity.setDictCode(dictEntity.getCode());
        // 设置字典项全路径
        entity.setFullPath(this.service.parseFullPath(item.getParentId(), entity.getId()));
        // 设置字典项排序值
        entity.setSortOrder(this.service.getMaxSortOrder(item.getParentId()) + 1);
        this.service.save(entity);
        return R.ok(entity.getId());
    }

    @Override
    @OperationLog(value = "删除字典项")
    @Transactional(rollbackFor = Exception.class)
    public R<Object> delete(String id) {
        DictItemDO entity = this.service.getById(id);
        if (null == entity) {
            return R.ok();
        }
        String dictType = this.dictService.getTypeById(entity.getDictId());
        if (DictTypeEnum.SYSTEM.name().equals(dictType)) {
            throw new FrameworkException(DictExceptionInfo.DELETE_SYSTEM_DICT_ITEM_IS_NOT_ALLOWED);
        }
        this.service.removeByFullPath(entity.getFullPath(), Me.tenantCode());
        return R.ok();
    }

    @Override
    @OperationLog(value = "更新字典项")
    @Transactional(rollbackFor = Exception.class)
    public R<Object> update(DictItemDTO item) {
        DictItemDO entity = this.service.getById(item.getId());
        if (null == entity) {
            throw new FrameworkException(DictExceptionInfo.DICT_ITEM_NOT_FOUND);
        }
        String tenantCode = Me.tenantCode();
        if (Boolean.TRUE.equals(this.service.labelExist(item.getDictId(), item.getId(), item.getValue(), tenantCode))) {
            throw new FrameworkException(DictExceptionInfo.DUPLICATE_DICT_ITEM_LABEL);
        }
        DictItemDO newEntity = Tools.Bean.copy(item, DictItemDO.class);
        newEntity.setFullPath(this.service.parseFullPath(item.getParentId(), item.getId()));
        this.service.updateById(newEntity);
        if (!newEntity.getPreset().equals(item.getPreset())) {
            this.service.updateChildrenPreset(newEntity.getPreset(), newEntity.getFullPath(), tenantCode);
        }
        return R.ok();
    }

    @Override
    public R<List<DictItemDTO>> page(DictItemQueryParamDTO queryParam) {
        return R.ok(this.service.listPage(queryParam, Me.tenantCode()).convert(entity -> Tools.Bean.copy(entity, DictItemDTO.class)));
    }

    @Override
    public R<List<DictItemDTO>> all() {
        return R.ok(DomainEnum.PLATFORM.name().equals(Me.domainCode()) ?
                Tools.Array.convertList(DictItemEnum.values(), dictItem -> {
                    DictItemDTO item = new DictItemDTO();
                    item.setId(Tools.Id.uuid());
                    item.setLabel(dictItem.description);
                    item.setValue(dictItem.name());
                    item.setDictCode(dictItem.dict.name());
                    return item;
                }) :
                Tools.Coll.convertList(this.service.listByTenantCode(Me.tenantCode()), entity -> Tools.Bean.copy(entity, DictItemDTO.class)));
    }

    @Override
    public R<DictItemDTO> detail(String id) {
        DictItemDO entity = this.service.getById(id);
        if (null == entity) {
            throw new FrameworkException(DictExceptionInfo.DICT_ITEM_NOT_FOUND);
        }
        return R.ok(Tools.Bean.copy(entity, DictItemDTO.class));
    }

    @Override
    public R<List<DictItemDTO>> listByDictId(String dictId) {
        return R.ok(Tools.Coll.convertList(this.service.listByDictId(dictId), entity -> Tools.Bean.copy(entity, DictItemDTO.class)));
    }

    @Override
    public R<List<DictItemDTO>> listByDictCodes(BatchParam<String> dictCodes) {
        return R.ok(Tools.Coll.convertList(this.service.listByDictCodes(dictCodes.getList(), Me.tenantCode()), entity -> Tools.Bean.copy(entity, DictItemDTO.class)));
    }

    @Override
    public R<Object> drag(DragOrderParam dragParam) {
        DragHelper<DictItemDO> dragHelper = DragHelperBuilder.builder(
                        () -> this.service.gt(dragParam.getParentId(), dragParam.getCurrentOrder()),
                        () -> this.service.gt(dragParam.getTargetParentId(), dragParam.getTargetOrder()),
                        (starOrder, endOrder) -> this.service.between(dragParam.getParentId(), starOrder, endOrder)
                )
                .which(dragParam.getParentId(), dragParam.getTargetParentId(), DragTargetPositionEnum.INNER.equals(dragParam.getPosition()))
                .currentNode(() -> this.service.getById(dragParam.getCurrentId()))
                .targetNode(() -> this.service.getById(dragParam.getTargetId()))
                .maxSortOrder(() -> this.service.getMaxSortOrder(dragParam.getTargetId()))
                .beforeTarget(DragTargetPositionEnum.BEFORE.equals(dragParam.getPosition()))
                .build();
        this.service.updateBatchById(dragHelper.drag());
        return R.ok();
    }
}
